package edu.luc.concordia;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.StringWriter;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Text;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax.helpers.XMLReaderFactory;

/**
 * Copyright 2008 Project Concordia
 * <p>
 * This file is part of RetailReturnSystem.
 * <p>
 * RetailReturnSystem is free software: you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation, either version 3 of the License, or (at your option) any
 * later version.
 * <p>
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 * <p>
 * You should have received a copy of the GNU General Public License along with
 * this program. If not, see <a
 * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.
 * <hr>
 * Read the Receipt file and Calculate Appropriate Refund amount and write back
 * to return receipt file.
 * 
 * @author Piyusha Desai
 * @version 0.1 2008-11-20
 */
public class Returns 
{
	// Variable Declaration
	private ArrayList<String> myReturnReceipt = new ArrayList();
	private ArrayList<Product> myReturnItems = new ArrayList();

	// Class Constructor , Initializes variable and read XML file
	public Returns(ArrayList<Product> items) 
	{
		myReturnItems = items;
		try 
		{ // XML file reader to read receipt file
			XMLReader xr = XMLReaderFactory.createXMLReader();
			SAXCounter pr = new SAXCounter();
			xr.setContentHandler(pr);
			xr.parse(new InputSource(new FileReader("receipt.XML")));

		} 
		catch (Exception e) 
		{
			e.printStackTrace();
		}
	}

	/**
	 * This method will determine fraud. Also calculate refund amount for scan
	 * items.
	 */
	private void calculateReturn() 
	{
		double refund = 0.0;
		if (myReturnItems.size() > 0) 
		{
			myReturnReceipt.add("fraud");
		}// if fraud found then add in receipt file
		else 
		{
			for (int i = 0; i < myReturnItems.size(); i++) 
			{
				Product tempProduct = myReturnItems.get(i);
				String description = tempProduct.getDescription();
				String uid = tempProduct.getUID();
				ArrayList<PriceScheme> priceScheme = tempProduct.getPriceScheme();
				double price = 0.0;
				myReturnReceipt.add(uid + " " + description + " " + price);

				refund = refund + price;
			}// refund calculation
		}
		myReturnReceipt.add("SubTotal = $" + String.format("%.2f", refund));

	}

	/**
	 * Write Receipt information in ReturnReceipt file
	 */
	private void updateReturnFile() 
	{
		FileWriter writer = null;
		double subTotal = 0.0;
		double tax = 0.0;
		double total = 0.0;

		// Creating an empty XML Document
		DocumentBuilderFactory dbfac = DocumentBuilderFactory.newInstance();
		DocumentBuilder docBuilder = null;
		try 
		{
			docBuilder = dbfac.newDocumentBuilder();

		} 
		catch (ParserConfigurationException e) 
		{
			e.printStackTrace();
		}
		Document doc = docBuilder.newDocument();

		// Creating the XML tree
		// create the root element and add it to the document
		Element root = doc.createElement("ReturnReceipt");
		doc.appendChild(root);

		try 
		{
			writer = new FileWriter("returns.xml", true);
		} 
		catch (IOException e1) 
		{
			e1.printStackTrace();
		}

		for (int i = 0; i < myReturnItems.size(); i++) 
		{

			Product tempProduct = myReturnItems.get(i);

			String uid = tempProduct.getUID();
			Element child1 = doc.createElement("uid");
			root.appendChild(child1);
			Text text1 = doc.createTextNode(uid);
			child1.appendChild(text1);

			String description = tempProduct.getDescription();
			Element child2 = doc.createElement("description");
			root.appendChild(child2);
			Text text2 = doc.createTextNode(description);
			child2.appendChild(text2);

			ArrayList<PriceScheme> priceScheme = tempProduct.getPriceScheme();
			double price = 0.0;
			subTotal += price;
			String totalPriceString = Double.toString(subTotal);
			Element child4 = doc.createElement("subTotal");
			root.appendChild(child4);
			Text text4 = doc.createTextNode(totalPriceString);
			child4.appendChild(text4);

			String refund = Double.toString(total);
			Element child6 = doc.createElement("refund");
			root.appendChild(child6);
			Text text6 = doc.createTextNode(refund);
			child6.appendChild(text6);

			// Output the XML
			// set up a transformer
			TransformerFactory transfac = TransformerFactory.newInstance();
			Transformer trans = null;
			try 
			{
				trans = transfac.newTransformer();

			} 
			catch (TransformerConfigurationException e) 
			{
				e.printStackTrace();
			}
			trans.setOutputProperty(OutputKeys.INDENT, "yes");

			// create string from xml tree
			StringWriter sw = new StringWriter();
			StreamResult result = new StreamResult(sw);
			DOMSource source = new DOMSource(doc);
			try 
			{
				trans.transform(source, result);

			} 
			catch (TransformerException e) 
			{
				e.printStackTrace();
			}
			String xmlString = sw.toString();

			try 
			{
				writer.write(xmlString);
				writer.flush();
			} 
			catch (IOException e) 
			{
				e.printStackTrace();
			}
		}
		try 
		{
			writer.close();
		} 
		catch (IOException e) 
		{
			e.printStackTrace();
		}
	}

	/**
	 * Call CalculateReturn() for refund calculation and updateReturnFile() for
	 * writing in XML file
	 * 
	 * @return items from myReturnReceipt to display in return receipt
	 */
	public ArrayList<String> generateReturnReceipt() 
	{
		calculateReturn();
		updateReturnFile();
		return myReturnReceipt;
	}

	/**
	 * XML Parser
	 */
	private class SAXCounter extends DefaultHandler 
	{
		// Variable declaration
		private HashMap<String, ReceiptInfo> receipts;
		private String contents;
		private ReceiptInfo receiptInfo;

		/**
		 * Class constructor.
		 */
		public SAXCounter() 
		{
			receipts = new HashMap<String, ReceiptInfo>();
			contents = "";
			ArrayList<String> rows = new ArrayList<String>();
		}

		/**
		 * Indication of first element of XML file
		 */
		public void startElement(String sname,String qname) throws SAXException 
		{
			String ename = sname;
			if ("".equals(ename))
				ename = qname;
			if (ename.equals("finalReceipt")) 
			{
				receiptInfo = new ReceiptInfo();
			}
		}

		/**
		 * All elements preceding first element in XML file
		 */
		public void endElement(String sName, String qName)
				throws SAXException 
		{
			String eName = sName;
			if ("".equals(eName))
				eName = qName;
			if (eName.equals("finalReceipt")) 
			{
				receipts.put(receiptInfo.uid, receiptInfo);
			}// when the parser encounters </finalreceipt>,add the receiptInfo
				// to hashmap
			if (eName.equals("uid")) 
			{
				receiptInfo.uid = contents;
			} // when the parser encounters </uid>,record uid
			if (eName.equals("description")) 
			{
				receiptInfo.description = contents;
			}// when the parser encounters </description>,record description
			if (eName.equals("subTotal")) 
			{
				receiptInfo.subTotal = contents;
			}// when the parser encounters </subTotal>,record subTotal
			if (eName.equals("gstTax")) 
			{
				receiptInfo.gstTax = contents;
			}// when the parser encounters </gstTax>,record gstTax
			if (eName.equals("total")) 
			{
				receiptInfo.total = contents;
			}// when the parser encounters </total>,record total

		}

		/**
		 * Method for Content formatting
		 * 
		 */
		public void characters(char[] buf, int offset, int len)
				throws SAXException 
		{
			contents = new String(buf, offset, len).trim();
		}

	}

}
